﻿using System;
using System.Threading;
using WindowServices.Server.Interface;

namespace WindowServices.Common
{
    /// <summary>
    /// SecuritySwitchThread is a thread wrapper class. It allows
    /// developers to customize the way a new thread is started and 
    /// ThreadStart object is invoked.
    /// </summary>
    public sealed class SecuritySwitchThread : IDisposable
    {
        private readonly ThreadStart _serviceDelegate;
        private readonly Thread _thread;
        SecurityUtility _su;


        readonly ServiceEntityEx _serviceEntity;

        /// <summary>
        /// The constructor takes more than one parameter
        /// as oppose to only one parameter is the bare bone Thread
        /// class. This allow we to perform some additional service
        /// based on the additional parameters, in our case, we will pass
        /// the configuration data that contains the user account information
        /// which is later used to perform the thread's security switch
        /// </summary>
        /// <param name="start">the ThreadStart delegate for the target method</param>
        /// <param name="serviceEntity"></param>
        public SecuritySwitchThread(ThreadStart start, ServiceEntityEx serviceEntity)
        {
            _serviceDelegate = start;
            _serviceEntity = serviceEntity;
            //create a new thread that calls the WrappingMethod
            _thread = new Thread(WrappingMethod);
        }
        public void Start()
        {
            //start the thread.
            _thread.Start();
        }

        /// <summary>
        /// WrappingMethod wraps performs the security
        /// switch and then invokes the ThreadStart delegate.
        /// </summary>
        private void WrappingMethod()
        {
            if (!_serviceEntity.Inheritance)
            {
                _su = new SecurityUtility();
                _su.Switch(_serviceEntity.UserInfo.UserId, _serviceEntity.UserInfo.PassWord, _serviceEntity.UserInfo.Domain);
            }
            //invoke the ThreadStart delegate object passed in 
            //on the class constructor
            _serviceDelegate();
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (_thread != null)
            {
                if (_thread.IsAlive)
                {
                    _thread.Abort();
                }                
            }
            if (_su != null)
            {
                _su.UndoSwitch();
            }
        }

        #endregion
    }
}
